<?php
/**
 * Authentication Class
 *
 * authentication_config.php must be autoloaded in autoload.php
 * Session must be autoloaded
 * REQUIRES Synt4x-Model
 *
 * @author Ian Murray
 */
class Authentication {
  /**
   * Variable que contiene los datos del usuario logueado o falso sino.
   *
   * @var string
   */
  var $user = FALSE;
  
  /**
   * Constructor de la clase authentication.
   *
   * @return void
   * @author Ian Murray
   */
  function Authentication()
  {
    $this->user = $this->user(TRUE);
  }
  
  /**
   * Funcion usada para obtener a CodeIgniter.
   * En php4 es necesario llamarla en otra funcion que no sea el constructor,
   * o sino puede haber errores, por eso se hara asi en esta clase.
   *
   * @return void
   * @author Ian Murray
   */
  /*function &CI() {
    return get_instance();
  }*/
  
  /**
   * Shortcut para obtener un key de la config de authentication
   *
   * @param string $key 
   * @return mixed
   * @author Ian Murray
   */
  function get_config($key) {
    $CI =& get_instance();
    return $CI->config->item($key, 'authentication');
  }
  
  /**
   * Intenta hacer login
   *
   * @param string $id 
   * @param string $password 
   * @param array $validations estado de otros camposd de la tabla que sean necesarios, como active = 1
   * @return boolean TRUE si ingreso exitosamente.
   * @author Ian Murray
   */
  function login($username, $password, $validations = null)
  {
    $CI =& get_instance();
    # Encrypt passsword if necessary
    if($this->get_config('autoencrypt')) {
      $password = md5($this->get_config('salt') . $password);
    }
    
    # Try to login
    $CI->load->model($this->get_config('model'), 'User');
    
    $data = array(
      'fields' => '*',
      'where' => array(
        $this->get_config('username') => $username,
        $this->get_config('password') => $password
      ),
      'limit' => 1
    );
    
    if(is_array($validations)) {
      foreach($validations as $field => $value) {
        $data['where'][$field] = $value;
      }
    }
    
    $user = $CI->User->get($data);
    
    if(count($user) == 1) {
      # Successful login!
      # Get group data if neccesary
      
      if($this->get_config('user_groups') && $this->get_config('user_groups_table') !== FALSE) {
        $CI->load->model($this->get_config('user_groups_table'), 'Group');
        
        $group = $CI->Group->get(array(
          'field' => '*',
          'where' => array(
            $this->get_config('user_groups_table_id') => $user[0][$this->get_config('user_groups_table_fk')]
          ),
          'limit' => 1 # Only support 1 group per user
        ));
        
        $CI->session->set_userdata($this->get_config('session'), array(
          'logged_in' => TRUE,
          'user' => $user[0],
          'group' => $group[0]
        ));
      }
      else {
        $CI->session->set_userdata($this->get_config('session'), array(
          'logged_in' => TRUE,
          'user' => $user[0]
        ));
      }
      
      $this->user = $this->user();
      
      return TRUE;
    }
    else {
      # No user with that data
      return FALSE;
    }
  }
  
  /**
   * Logout loggedin user
   *
   * @return boolean
   * @author Ian Murray
   */
  function logout() 
  {
    $CI =& get_instance();
    $CI->session->unset_userdata($this->get_config('session'));
    $this->user = FALSE;
    return TRUE;
  }
  
  /**
   * Requires that the user is logged in to continue, redirects
   * to login screen if not.
   *
   * @return boolean
   * @author Ian Murray
   */
  function require_login($redirect = TRUE)
  {
    $CI =& get_instance();
    if($this->logged_in()) {
      return TRUE;
    }
    else {
      if($redirect) {
        $CI->session->set_flashdata($this->get_config('flashdata'), $this->get_config('message_unauthorized'));
        
        /* Agregado para SGRAMOS */
        $CI->session->set_userdata('login_referer', $CI->uri->uri_string());
        
        redirect($this->get_config('login'));
      }

      return FALSE;
    }
  }
  
  /**
   * Makes sure logged in users belongs to any of the groups given.
   *
   * Needs user_groups set to TRUE
   *
   * Usage: Authentication::require_groups(array('admin', 'moderator'))
   * where 'admin' and 'moderator' are the values of the user_groups_table_field
   * or user_groups_table_type_field depending on configuration.
   *
   * @return void
   * @author Ian Murray
   */
  function require_groups($groups = array(), $redirect = TRUE)
  {
    $CI =& get_instance();

    if( ! $this->get_config('user_groups')) {
      return false;
    }
    
    if(count($groups) == 0) {
      # No user groups specified, only require login.
      return $this->require_login($redirect);
    }
    
    # Check user group of logged in user
    if($user = $this->user()) {
      if( ! $this->get_config('user_groups_table')) {
        # Using only field in users table
        if(in_array($user[$this->get_config('user_groups_table_field')], $groups)) {
          # User belongs to group
          return TRUE;
        }
      }
      else {
        # Groups are managed through group table
        $group = $this->group();
        if(in_array($group[$this->get_config('user_groups_table_type_field')], $groups)) {
          return TRUE;
        }
      }
    }
    
    # If reached here then error, return false and / or redirect
    if($redirect) {
      $CI->session->set_flashdata($this->get_config('flashdata'), $this->get_config('message_unauthorized'));
      redirect($this->get_config('login'));
    }

    return FALSE;
  }
  
  /**
   * Checks if user is logged in
   *
   * @return boolean
   * @author Ian Murray
   */
  function logged_in()
  {
    $CI =& get_instance();
    $session = $CI->session->userdata($this->get_config('session'));
    
    if( $session ) {
       $CI->load->model($this->get_config('model'), 'User');

      $user = $CI->User->get(array(
        'fields' => '*',
        'where' => $session['user'], # Check entire array against database, to ensure noone tampered with it
        'limit' => 1
      ));
      
      if($session['logged_in'] && count($user) == 1) {
        return TRUE;
      }
    }
    
    # Not logged in if reached here.
    return FALSE;
  }
  
  /**
   * Returns user info array or false if not logged in
   *
   * @param boolean group return group table data if possible
   * @return mixed
   * @author Ian Murray
   */
  function user($group = false)
  {
    $CI =& get_instance();
    if($this->logged_in()) {
      $session = $CI->session->userdata($this->get_config('session'));
      
      if($this->get_config('user_groups_table') !== FALSE && $group) {
        return array('user' => $session['user'], 'group' => $session['group']);
      }
      else {
        return $session['user'];
      }
    }
    else {
      return FALSE;
    }
  }
  
  /**
   * Get the group info from user if using group table
   *
   * @return void
   * @author Ian Murray
   */
  function group()
  {
    $CI =& get_instance();
    if($this->logged_in() && $this->get_config('user_groups_table') !== FALSE) {
      $session = $CI->session->userdata($this->get_config('session'));
      return $session['group'];
    }
    else {
      return FALSE;
    }
  }

  /**
   * Salts password with configuration salt
   *
   * @param string $password 
   * @return void
   * @author Ian Murray
   */
  function salt($password)
  {
    return md5($this->get_config('salt') . $password);
  }
  
  /**
   * Alias para salt ... podria llegar a ser ambiguo el nombre de esa funcion.
   *
   * @param string $password 
   * @return void
   * @author Ian Murray
   */
  function encrypt($password)
  {
    return $this->salt($password);
  }
}